﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace NuMetaheuristics.Utility
{
    public class ConsoleTypeBuilder : TypeBuilderBase
    {
        override protected void displayTypeConstructor(ConstructorInfo ctor)
        {
            ParameterInfo[] parameters = ctor.GetParameters();
            foreach (ParameterInfo param in parameters)
            {
                Console.WriteLine("\t" + param);
            }
        }

        override protected void displayTypeProperty(PropertyInfo property)
        {
            Console.WriteLine("property: {0}", property);
            Console.WriteLine("  attributes: {0}", property.Attributes);
        }

        override protected void displayObjectProperty(object theObj, PropertyInfo property)
        {
            object value = property.GetValue(theObj, new object[]{});
            Console.WriteLine("property: {0}", property.Name);
            Console.WriteLine("  value: {0}", value);
        }

        override protected void displayObjectField(object theObj, FieldInfo field)
        {
            object value = field.GetValue(theObj);
            Console.WriteLine("field: {0}", field.Name);
            Console.WriteLine("  value: {0}", value);
        }

        override protected void displayError(string error)
        {
            Console.WriteLine(error);
        }
        override protected Type chooseType(Type[] types)
        {
            int typeNum = 0;
            Console.WriteLine("Types: ");
            foreach (Type type in types)
            {
                Console.WriteLine("  {0}. {1}", typeNum, type);

                typeNum++;
            }
            Console.WriteLine();

            int choice = promptForInt("Choose a type");
            while (choice > types.Length)
            {
                Console.WriteLine("Error: choose between 0 and {0}", types.Length);
                choice = promptForInt("Choose a type");
            }

            return types[choice];
        }

        override protected object chooseInstance(object[] instances)
        {
            int num = 0;
            Console.WriteLine("Instances: ");
            foreach (object instance in instances)
            {
                Console.WriteLine("  {0}. {1}", num, instance);
                num++;
            }
            Console.WriteLine();

            int choice = promptForInt("Choose an instance");
            while (choice > instances.Length)
            {
                Console.WriteLine("Error: choose between 0 and {0}", instances.Length);
                choice = promptForInt("Choose an instance");
            }

            return instances[choice];
        }

        override protected ConstructorInfo chooseConstructor(ConstructorInfo[] ctors)
        {
            int num = 0;
            Console.WriteLine("Constructors: ");
            foreach (ConstructorInfo ctor in ctors)
            {
                Console.WriteLine("  " + num.ToString() + ". " + ctor);

                num++;
            }
            Console.WriteLine();

            int choice = promptForInt("Choose a constructor");
            while (choice > ctors.Length)
            {
                Console.WriteLine("Error: choose between 0 and {0}", ctors.Length);
                choice = promptForInt("Choose a constructor");
            }

            return ctors[choice];
        }

        override protected int promptForInt(string descr)
        {
            int rv;
            bool success;

            string prompt = descr + ": enter an int: ";
            do
            {
                Console.Write(prompt);
                string input = Console.ReadLine();

                success = Int32.TryParse(input, out rv);
                if (!success)
                {
                    Console.WriteLine("Error. Must enter a valid int");
                }

            } while (!success);

            return rv;
        }

        override protected double promptForDouble(string descr)
        {
            double rv;
            bool success;

            string prompt = descr + ": enter a double: ";
            do
            {
                Console.Write(prompt);
                string input = Console.ReadLine();

                success = Double.TryParse(input, out rv);
                if (!success)
                {
                    Console.WriteLine("Error. Must enter a valid double");
                }

            } while (!success);

            return rv;
        }

        override protected string promptForString(string descr)
        {
            string prompt = descr + ": enter any string: ";
            Console.Write(prompt);
            return Console.ReadLine();
        }

        override protected bool promptForBool(string descr)
        {
            bool rv;
            bool success;

            string prompt = descr + ": enter true/false: ";
            do
            {
                Console.Write(prompt);
                string input = Console.ReadLine();

                success = Boolean.TryParse(input, out rv);
                if (!success)
                {
                    Console.WriteLine("Error. Must enter true/false");
                }

            } while (!success);

            return rv;
        }

        override protected void modifyObjectProperties(object theObj)
        {
            Type type = theObj.GetType();
            foreach(PropertyInfo property in type.GetProperties())
            {
                displayObjectProperty(theObj, property);

                if (promptForBool("Modify property?"))
                {
                    Type propertyType = property.PropertyType;
                    object obj = CreateType(propertyType);

                    property.SetValue(theObj, obj, new object[] { });
                }
            }
        }
    }
}
